package com.zidongxiangxi.clock.server.job;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zidongxiangxi.clock.server.business.ClockBusiness;
import com.zidongxiangxi.clock.server.config.ClockConfig;
import com.zidongxiangxi.clock.server.manager.ClockTaskManger;
import com.zidongxiangxi.clock.server.repository.entity.Clock;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 闹钟响铃工作线程
 *
 * @author chenxudong
 * @date 2020/07/24
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RingClockWorkThread extends AbstractWorkThread {
    private final ClockConfig config;

    private final ClockBusiness clockBusiness;
    private final ClockTaskManger alarmClockTaskManger;

    private final StringRedisTemplate redisTemplate;

    /**
     * 一秒
     */
    private static final int ONE_SECOND = 1000;

    /**
     * 线程是否结束
     */
    private volatile boolean stop = false;

    @Override
    public void run() {
        log.info("start {} ........", this.getClass().toString());
        while (!isStop()) {
            long startMillis = System.currentTimeMillis();
            try {
                //取出响铃时间为当前秒数的任务
                List<Clock> clocks = alarmClockTaskManger.getClockTask().stream()
                    .filter(alarmClock -> alarmClock.getLatestRingAt() <= startMillis)
                    .collect(Collectors.toList());

                // 处理任务
                if (CollectionUtils.isNotEmpty(clocks)) {
                    //删除任务
                    alarmClockTaskManger.removeClockTask(clocks);

                    //异步发送
                    List<List<Clock>> clocksListList = Lists.partition(clocks, config.getCallbackMaxBatchSize());
                    long batchBeginTime = System.currentTimeMillis() / 1000;
                    for (List<Clock> clockList : clocksListList) {
                        clockBusiness.ringClockAsync(clockList, batchBeginTime);
                    }
                }

                // 计算睡眠时间
                long costMillis = System.currentTimeMillis() - startMillis;
                if (ONE_SECOND > costMillis) {
                    log.info("AlarmCLockRIngWorkThread sleep " + (ONE_SECOND - costMillis));
                    Thread.sleep(ONE_SECOND - costMillis);
                }
            } catch (InterruptedException ignore) {
                log.error("AlarmClockRingWorkThread is interrupted !");
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                log.error("AlarmClockRIngWorkThread error , message =  ", e);
            }
        }
        log.info("stop {} ........", this.getClass().toString());
    }

    @Override
    public void stop() {
        stop = true;
    }

    @Override
    public boolean isStop() {
        return stop;
    }

}
